package com.ansion.commonchat.startup.fresco.fetcher;

import android.annotation.SuppressLint;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;

import com.ansion.groovy.GroovyArray;
import com.ansion.log.VLog;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.producers.Consumer;
import com.facebook.imagepipeline.producers.FetchState;
import com.facebook.imagepipeline.producers.HttpUrlConnectionNetworkFetcher;
import com.facebook.imagepipeline.producers.NetworkFetcher;
import com.facebook.imagepipeline.producers.ProducerContext;
import com.facebook.imagepipeline.request.ImageRequest;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;


/**
 * Description:
 * <p>
 * Created by ____lamer on 2019-11-28 13:49
 */
public class FrescoFetcherExtension implements NetworkFetcher<FetchState>, Comparator<IFrescoFetcher<? extends FetchState>> {

    private static final FrescoFetcherExtension INSTANCE = new FrescoFetcherExtension();
    private static final String TAG = "FrescoFetcherExtension";

    public static FrescoFetcherExtension get() {
        return INSTANCE;
    }

    @NonNull
    private final List<IFrescoFetcher<? extends FetchState>> mFetchers;
    @Nullable
    private NetworkFetcher mDefaultFetcher;

    private FrescoFetcherExtension() {
        this.mFetchers = new ArrayList<>();
    }

    /**
     * must be call on ui thread
     */
    @UiThread
    public void register(@NonNull IFrescoFetcher<? extends FetchState> fetcher) {
        if (mFetchers.contains(fetcher)) {
            if (VLog.OPEN_LOG) {
                VLog.d(TAG, "fetcher already added... (%s)", fetcher.getClass().getSimpleName());
            }
            return;
        }
        synchronized (mFetchers) {
            mFetchers.add(fetcher);
            if (GroovyArray.count(mFetchers) > 1) {
                //降序排列，越小越先执行
                Collections.sort(mFetchers, this);
            }
            if (VLog.OPEN_LOG) {
                VLog.d(TAG, "Fresco fetcher order (%s)", GroovyArray.join(mFetchers, ",", it -> it.getClass().getSimpleName()));
                //如果是debug，检查一下 order id必须不一样
                GroovyArray.each(mFetchers, it -> {
                    if (GroovyArray.any(mFetchers, (index, item) -> it.order() == item.order() && it != item)) {
                        @SuppressLint("DefaultLocale") String errorTips = String.format("register failure !!! fetcher(%s) order(%d) duplicate", it.getClass().getSimpleName(), it.order());
                        throw new IllegalArgumentException(errorTips);
                    }
                });
            }
        }
    }

    @WorkerThread
    @Override
    public FetchState createFetchState(Consumer<EncodedImage> consumer, ProducerContext producerContext) {
        ImageRequest request = producerContext.getImageRequest();
        return getFetcher(request).createFetchState(consumer, producerContext);
    }

    @WorkerThread
    @Override
    public void fetch(FetchState fetchState, Callback callback) {
        ImageRequest request = fetchState.getContext().getImageRequest();
        getFetcher(request).fetch(fetchState, callback);
    }

    @Override
    public boolean shouldPropagate(FetchState fetchState) {
        ImageRequest request = fetchState.getContext().getImageRequest();
        return getFetcher(request).shouldPropagate(fetchState);
    }

    @Override
    public void onFetchCompletion(FetchState fetchState, int byteSize) {
        ImageRequest request = fetchState.getContext().getImageRequest();
        getFetcher(request).onFetchCompletion(fetchState, byteSize);
    }

    @Override
    public Map<String, String> getExtraMap(FetchState fetchState, int byteSize) {
        ImageRequest request = fetchState.getContext().getImageRequest();
        return getFetcher(request).getExtraMap(fetchState, byteSize);
    }

    @NonNull
    private NetworkFetcher<FetchState> getDefaultFetcher() {
        if (mDefaultFetcher == null) {
            synchronized (FrescoFetcherExtension.class) {
                if (mDefaultFetcher == null) {
                    mDefaultFetcher = new HttpUrlConnectionNetworkFetcher();
                }
            }
        }
        return mDefaultFetcher;
    }

    @NonNull
    private NetworkFetcher<FetchState> getFetcher(ImageRequest request) {
        NetworkFetcher fetcher;
        synchronized (mFetchers) {
            fetcher = GroovyArray.find(mFetchers, it -> it.interrupt(request));
        }
        if (fetcher == null) {
            fetcher = getDefaultFetcher();
        }
        if (VLog.OPEN_LOG) {
            VLog.d(TAG, "Fresco use fetcher(%s)", fetcher.getClass().getSimpleName());
        }

        return fetcher;
    }

    @Override
    public int compare(IFrescoFetcher<? extends FetchState> o1, IFrescoFetcher<? extends FetchState> o2) {
        return o1.order() - o2.order();
    }
}
